package com.feixc.xsimple.eventx;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 事件分发器<br>
 * <br>
 * 在代码中初始化（只需初始化一次），参数为事件处理器类的包名：<br>
 * {@code EventDispatcher.init("xxx.yyy.zzz")} <br>
 * <br>
 * 或在spring配置文件中实例化：
 * 
 * <pre>
 * {@code
 * <bean id="eventDispatcher" class="org.opensource.xsimple.eventx.EventDispatcher">
 *     <constructor name="handlerPackage" value="xxx.yyy.zzz" />
 * </bean>
 * }
 * </pre>
 * 
 * @author xuzhigang01
 */
public class EventDispatcher {
	private static final Logger LOG = LoggerFactory.getLogger(EventDispatcher.class);

	private static Map<Class<?>, Object> handlerMap = new HashMap<Class<?>, Object>();
	private static Map<String, EventHandleMethod> handleMethodMap = new HashMap<String, EventHandleMethod>();

	private static ExecutorService handlePool;

	public EventDispatcher() {
	}

	/**
	 * @param handlerPackage
	 *            事件处理器类所在的包
	 */
	public EventDispatcher(String handlerPackage) {
		init(handlerPackage);
	}

	/**
	 * 初始化事件分发器
	 * 
	 * @param handlerPackage
	 *            事件处理器类所在的包
	 */
	public static void init(String handlerPackage) {
		// 载入事件处理类
		List<Class<?>> classes = ClassLoadUtil.LoadClasses(handlerPackage, true);
		if (classes.isEmpty()) {
			LOG.warn("load 0 class from {}", handlerPackage);
		}

		// 解析事件处理类
		for (Class<?> clazz : classes) {
			EventHandler handlerAnno = clazz.getAnnotation(EventHandler.class);
			if (handlerAnno == null) {
				continue;
			}
			String module = handlerAnno.value();

			Object obj = null;
			try {
				obj = clazz.newInstance();
			} catch (Exception e) {
				LOG.error("initialize " + clazz.getSimpleName() + " error", e);
				continue;
			}
			handlerMap.put(clazz, obj);

			Method[] methods = clazz.getDeclaredMethods();
			for (Method method : methods) {
				Event eventAnno = method.getAnnotation(Event.class);
				if (eventAnno != null) {
					String eventName = eventAnno.value();

					String eventUri = null;
					if (eventName.startsWith("/")) {
						eventUri = eventName;
					} else {
						eventUri = module + "/" + eventName;
					}
					handleMethodMap.put(eventUri, new EventHandleMethod(obj, method, eventUri, eventAnno.priority()));
					LOG.info("find eventURI [{}] 's handle method [{}.{}]", eventUri, clazz.getSimpleName(),
							method.getName());
				}
			}
		}

		// 初始化事件处理线程池
		int nThreads = Runtime.getRuntime().availableProcessors();
		handlePool = new ThreadPoolExecutor(nThreads, nThreads * 2, 0L, TimeUnit.MILLISECONDS, new EventHandleQueue());
	}

	/**
	 * 分发事件
	 * 
	 * @param eventUri
	 *            事件URI
	 * @param eventParams
	 *            事件参数
	 */
	protected static void dispartchEvent(String eventUri, Map<String, Object> eventParams) {
		EventHandleMethod handleMethod = handleMethodMap.get(eventUri);
		if (handleMethod == null) {
			LOG.warn("can not find eventHandleMethod by eventUri: {}", eventUri);
			return;
		}

		handlePool.execute(new EventHandleTask(handleMethod, eventParams));
	}

	protected static Object getHandler(Class<?> clazz) {
		return handlerMap.get(clazz);
	}
}
